package com.movie.service;

import com.movie.dto.ActorDTO;
import com.movie.dto.MovieDTO;
import com.movie.dto.MovieSourceDTO;
import com.movie.dto.MovieSubtitleDTO;
import com.movie.entity.*;
import com.movie.repository.ActorRepository;
import com.movie.repository.CategoryRepository;
import com.movie.repository.MovieRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class MovieService {
    
    private final MovieRepository movieRepository;
    private final CategoryRepository categoryRepository;
    private final ActorRepository actorRepository;
    
    public Page<MovieDTO> findAll(Pageable pageable) {
        return movieRepository.findAll(pageable)
                .map(this::convertToDTO);
    }
    
    public MovieDTO findById(Long id) {
        Movie movie = movieRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("影片不存在"));
        return convertToDTO(movie);
    }
    
    @Transactional
    public MovieDTO create(MovieDTO movieDTO) {
        // 检查影片名称是否已存在
        if (movieRepository.findByTitle(movieDTO.getTitle()).isPresent()) {
            throw new RuntimeException("影片名称已存在");
        }
        
        // 验证分类是否存在
        if (movieDTO.getCategoryId() != null) {
            categoryRepository.findById(movieDTO.getCategoryId())
                    .orElseThrow(() -> new RuntimeException("分类不存在"));
        }
        
        Movie movie = convertToEntity(movieDTO);
        
        // 处理演员关联
        if (movieDTO.getActors() != null && !movieDTO.getActors().isEmpty()) {
            List<String> actorNames = movieDTO.getActors().stream()
                    .map(ActorDTO::getName)
                    .collect(Collectors.toList());
            List<Actor> actors = findOrCreateActors(actorNames);
            movie.setActors(actors);
        }
        
        Movie saved = movieRepository.save(movie);
        return convertToDTO(saved);
    }
    
    @Transactional
    public MovieDTO update(Long id, MovieDTO movieDTO) {
        Movie existing = movieRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("影片不存在"));
        
        // 检查影片名称是否被其他影片使用
        if (!existing.getTitle().equals(movieDTO.getTitle()) && 
            movieRepository.findByTitle(movieDTO.getTitle()).isPresent()) {
            throw new RuntimeException("影片名称已存在");
        }
        
        // 验证分类是否存在
        if (movieDTO.getCategoryId() != null) {
            categoryRepository.findById(movieDTO.getCategoryId())
                    .orElseThrow(() -> new RuntimeException("分类不存在"));
        }
        
        // 只复制基本属性，避免复制关联实体
        existing.setTitle(movieDTO.getTitle());
        existing.setYear(movieDTO.getYear());
        existing.setCover(movieDTO.getCover());
        existing.setDescription(movieDTO.getDescription());
        existing.setRating(movieDTO.getRating());
        existing.setStatus(movieDTO.getStatus());
        
        // 设置分类
        if (movieDTO.getCategoryId() != null) {
            Category category = categoryRepository.findById(movieDTO.getCategoryId())
                    .orElseThrow(() -> new RuntimeException("分类不存在"));
            existing.setCategory(category);
        }
        
        // 更新片源和字幕
        updateSources(existing, movieDTO.getSources());
        updateSubtitles(existing, movieDTO.getSubtitles());
        
        // 更新演员关联
        if (movieDTO.getActors() != null && !movieDTO.getActors().isEmpty()) {
            List<String> actorNames = movieDTO.getActors().stream()
                    .map(ActorDTO::getName)
                    .collect(Collectors.toList());
            List<Actor> actors = findOrCreateActors(actorNames);
            existing.getActors().clear();
            existing.getActors().addAll(actors);
        } else {
            // 如果没有演员数据，清空关联
            existing.getActors().clear();
        }
        
        Movie updated = movieRepository.save(existing);
        return convertToDTO(updated);
    }
    
    @Transactional
    public void delete(Long id) {
        Movie movie = movieRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("影片不存在"));
        movieRepository.delete(movie);
    }
    
    public Page<MovieDTO> findByStatus(String status, Pageable pageable) {
        return movieRepository.findByStatus(status, pageable)
                .map(this::convertToDTO);
    }
    
    public Page<MovieDTO> search(String keyword, Pageable pageable) {
        return movieRepository.findByTitleContaining(keyword, pageable)
                .map(this::convertToDTO);
    }
    
    public Page<MovieDTO> findByCategory(Long categoryId, Pageable pageable) {
        return movieRepository.findByCategoryId(categoryId, pageable)
                .map(this::convertToDTO);
    }
    
    public List<MovieDTO> findLatestPublishedMovies(Pageable pageable) {
        return movieRepository.findLatestPublishedMovies(pageable)
                .stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    public Page<MovieDTO> findMoviesWithFilters(
            String search, Long categoryId, String status, 
            Integer yearMin, Integer yearMax, Double ratingMin, Double ratingMax,
            String sortBy, String sortDir, Pageable pageable) {
        
        // 设置默认排序
        if (sortBy == null) {
            sortBy = "id";
        }
        if (sortDir == null) {
            sortDir = "asc";
        }
        
        // 构建动态查询
        Page<Movie> movies = movieRepository.findMoviesWithFilters(
            search, categoryId, status, yearMin, yearMax, ratingMin, ratingMax, sortBy, sortDir, pageable);
        
        return movies.map(this::convertToDTO);
    }
    
    private void updateSources(Movie movie, List<MovieSourceDTO> sourceDTOs) {
        movie.getSources().clear();
        if (sourceDTOs != null) {
            sourceDTOs.forEach(sourceDTO -> {
                MovieSource source = new MovieSource();
                BeanUtils.copyProperties(sourceDTO, source);
                source.setMovie(movie);
                movie.getSources().add(source);
            });
        }
    }
    
    private void updateSubtitles(Movie movie, List<MovieSubtitleDTO> subtitleDTOs) {
        movie.getSubtitles().clear();
        if (subtitleDTOs != null) {
            subtitleDTOs.forEach(subtitleDTO -> {
                MovieSubtitle subtitle = new MovieSubtitle();
                BeanUtils.copyProperties(subtitleDTO, subtitle);
                subtitle.setMovie(movie);
                movie.getSubtitles().add(subtitle);
            });
        }
    }
    
    private MovieDTO convertToDTO(Movie movie) {
        MovieDTO dto = new MovieDTO();
        BeanUtils.copyProperties(movie, dto);
        
        if (movie.getCategory() != null) {
            dto.setCategoryId(movie.getCategory().getId());
            dto.setCategoryName(movie.getCategory().getName());
        }
        
        // 转换演员
        dto.setActors(movie.getActors().stream()
                .map(actor -> {
                    ActorDTO actorDTO = new ActorDTO();
                    actorDTO.setId(actor.getId());
                    actorDTO.setName(actor.getName());
                    actorDTO.setAvatar(actor.getAvatar());
                    actorDTO.setDescription(actor.getDescription());
                    actorDTO.setNationality(actor.getNationality());
                    actorDTO.setBirthday(actor.getBirthday());
                    return actorDTO;
                })
                .collect(Collectors.toList()));
        
        // 转换片源
        dto.setSources(movie.getSources().stream()
                .map(source -> {
                    MovieSourceDTO sourceDTO = new MovieSourceDTO();
                    BeanUtils.copyProperties(source, sourceDTO);
                    return sourceDTO;
                })
                .collect(Collectors.toList()));
        
        // 转换字幕
        dto.setSubtitles(movie.getSubtitles().stream()
                .map(subtitle -> {
                    MovieSubtitleDTO subtitleDTO = new MovieSubtitleDTO();
                    BeanUtils.copyProperties(subtitle, subtitleDTO);
                    return subtitleDTO;
                })
                .collect(Collectors.toList()));
        
        return dto;
    }
    
    private Movie convertToEntity(MovieDTO dto) {
        Movie movie = new Movie();
        BeanUtils.copyProperties(dto, movie);
        
        if (dto.getCategoryId() != null) {
            categoryRepository.findById(dto.getCategoryId())
                    .ifPresent(movie::setCategory);
        }
        
        return movie;
    }
    
    private List<Actor> findOrCreateActors(List<String> actorNames) {
        return actorNames.stream()
                .map(name -> {
                    Optional<Actor> existingActor = actorRepository.findByName(name);
                    if (existingActor.isPresent()) {
                        return existingActor.get();
                    } else {
                        Actor newActor = new Actor();
                        newActor.setName(name);
                        newActor.setCreatedAt(LocalDateTime.now());
                        return actorRepository.save(newActor);
                    }
                })
                .collect(Collectors.toList());
    }
}